/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package chessboard;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import javax.swing.JOptionPane;

/**
 *
 * @author Jedrek
 */
class RobotController implements Runnable{
    
    ServerSocket server = null;
    Socket socket = null;
    final ArrayList<Socket> sockets = new ArrayList<Socket>();
    final ArrayList<String> commands = new ArrayList<String>();

    String returnCmd = null;
    
    boolean connected = false;
    final Object connectionLock = new Object();
    
    public boolean running = true;
    
    public RobotController(){
    }

    public void run(){
        Socket tmpSocket = null;
        InputStream in = null;
        OutputStream out = null;
        byte [] data = new byte[30];
        int dataCount = 0;
        String cmd = "";

        System.err.println("Robot controller started");
        
        try {
            //start server
            if(server != null)
                server.close();
            synchronized(this){
                if(socket != null)
                    socket.close();
            }
            server = new ServerSocket(4444);
            server.setSoTimeout(100);
            
            //waiting for connection
            System.err.println("Robot controller: waiting for connection");
            while(running){
                try{
                    tmpSocket = server.accept();
                    break;
                } catch(SocketTimeoutException ex){}
            }

            System.err.println("Robot controller: Connected to something");
        
            if(running){
                synchronized(this){
                    socket = tmpSocket;
                    socket.setSoTimeout(100);
                    in = socket.getInputStream();
                    out = socket.getOutputStream();
                }
//                server.close();
//                server = null;
            }
            
            //waiting for beginning of communication
            System.err.println("Robot controller: waiting for beginning of communication");
            while(!cmd.contains("ETI0K") && running){
                try{
                    dataCount = in.read(data);
                    if(dataCount<0){
                        throw new IOException("Client disctonnected");
                    }
                    cmd = new String(data, 0, dataCount);
                } catch(SocketTimeoutException ex){}
            }
            if(running)
                System.err.println("Robot controller: running!");
                synchronized(connectionLock){
                    connected = true;
                }
            
            while(running){
                try{
                    dataCount = in.read(data);
                    if(dataCount<0){
                        throw new IOException("Client disctonnected");
                    }
                    cmd = new String(data, 0, dataCount);
                    if(cmd.contains("WDG"))
                        out.write(data);
                    if(cmd.contains("ETI1K")){
                        closeConnection();
                        break;
                    }
                } catch(SocketTimeoutException ex){}
                
                synchronized(commands){
                    if(returnCmd != null){
                        if(cmd.contains(returnCmd)){
                            commands.remove(0);
                            returnCmd = null;
                        }
                    }
                    if(commands.size() > 0 && returnCmd==null){
                        System.err.println("Robot controller: sending: "+commands.get(0));
                        out.write(commands.get(0).getBytes());
                        returnCmd = commands.get(0);
                    }
                }
            }
        } catch (IOException ex) {
            closeConnection();
//            System.err.println(ex.getMessage());
            running = false;
//            JOptionPane.showMessageDialog(null, "Server failed. There will be no connection with robots.\nError:\n"+ex.getMessage());
            System.err.println("Server failed. There will be no connection with robots.\nError:\n"+ex.getMessage());
            return;
        }
    }
    
    /**
     * adds given command to list. If command which was send last time was confirmed then command at index 0 in list is sent
     * @param cmd command to send
     */
    public void sendCommand(String cmd){
        synchronized(commands){
            commands.add(cmd);
        }
    }
    
    /**
     * closes connection
     */
    public void closeConnection(){
//        if(sockets != null)
//            while(sockets.size() > 0){
//            try {
//                synchronized(sockets.get(sockets.size()-1)){
//                    sockets.get(sockets.size()-1).close();
//                }
//            } catch (IOException ex) {}
//                    sockets.remove(sockets.size()-1);
//            }
        System.err.println("Robot controller: closing connection");
        synchronized(connectionLock){
            connected = false;
        }
//        running = false;
        if(socket != null)
            try {
                synchronized(this){
                    socket.close();
                    socket = null;
                }
            } catch (IOException ex) {}
        if(server != null)
            try {
                server.close();
                server = null;
            } catch (IOException ex) {}
    }
    
    public boolean isConnected(){
        synchronized(connectionLock){
            return connected;
        }
    }

    public boolean isRobotBusy(){
        boolean returnValue = true;
        if(!running || !connected)
            return false;
        synchronized(commands){
            if(commands.size()<=0)
                returnValue = false;
        }
        return returnValue;
    }
}
